home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Ken Long / NewPong-c / Think / pong.c next >
Encoding:
C/C++ Source or Header  |  1994-12-04  |  16.0 KB  |  768 lines  |  [TEXT/KAHL]

  1. //• ——————————————————————————————•••———————————————————————————————•//
  2. //• Another old source project, brought back from the dead by        •//
  3. //• Kenneth A Long, at itty bitty bytes(tm)!                        •//
  4. //• ——————————————————————————————•••———————————————————————————————•//
  5.  
  6. // 18-Jun-88 14:52:30-MDT,16523;000000000001
  7. // Return-Path: <u-lchoqu%sunset@cs.utah.edu>
  8. // Received: from cs.utah.edu by SIMTEL20.ARPA with TCP; Sat, 18 Jun 88 14:52:07 MDT
  9. // Received: by cs.utah.edu (5.54/utah-2.0-cs)
  10. //     id AA22823; Sat, 18 Jun 88 14:52:05 MDT
  11. // Received: by sunset.utah.edu (5.54/utah-2.0-leaf)
  12. //     id AA24896; Sat, 18 Jun 88 14:52:01 MDT
  13. // Date: Sat, 18 Jun 88 14:52:01 MDT
  14. // From: u-lchoqu%sunset@cs.utah.edu (Lee Choquette)
  15. // Message-Id: <8806182052.AA24896@sunset.utah.edu>
  16. // To: rthum@simtel20.arpa
  17. // Subject: pong.c
  18.  
  19. /*            pong.c
  20.  The classic game of pong in Megamax C for the Mac.
  21.  Thanks to MacTutor (Vol 1, No. 5 April 1985 page 39) for 
  22.  animation techniques. If you are reading this and don't  
  23.  subscribe to MacTutor, consider it. No resource file is  
  24.  needed. This program, source and object, is in the
  25.  public domain and not for sale. 
  26.   
  27.  Author:    David L. O'Connor, 370 Eden St. Buffalo, N.Y. 
  28.             14220.  (716) 828-0898.   CIS - 70265,1172 
  29.  Date  :    July, 1985   Version 2 
  30. */
  31.  
  32. // #include    <mem.h>
  33. // #include    <qd.h>
  34. // #include    <qdvars.h>
  35. // #include    <event.h>
  36. // #include    <toolbox.h>
  37. // #include    <res.h>
  38. // #include    <win.h>
  39. // #include    <menu.h>
  40. #include    <stdio.h>
  41. #include    <sound.h>
  42.  
  43. /* the game directions */
  44. #define    STOPPED 0
  45. #define    UP 1
  46. #define    DOWN 2
  47. #define    LEFT 3
  48. #define    RIGHT 4
  49. #define    UP_LEFT 5
  50. #define    UP_RIGHT 6
  51. #define    DOWN_LEFT 7
  52. #define    DOWN_RIGHT 8
  53.  
  54. /* paddle + ball dimensions */
  55. #define    PADWIDTH 10
  56. #define    PADLENGTH 45
  57. #define    PADINSET 10
  58. #define    BALLWIDTH 9
  59. #define    BALLLENGTH 9
  60.  
  61. #define    BALLSPEED 7
  62. #define    PADDLESPEED 9
  63. #define    HIGHSCORE 21
  64.  
  65. /* the menu ids */
  66. #define    appleID 128    
  67. #define    fileID  129
  68. #define    editID  130
  69. #define    skillID 131
  70. #define    soundID 132
  71.  
  72. /* from the MAC's standard pattern list */
  73. #define    PAD_PAT ((*pat_handle)->pat_list[6])
  74. #define    WALL_PAT ((*pat_handle)->pat_list[4])
  75.  
  76. typedef struct{
  77.     int pat_cnt;
  78.     Pattern pat_list[38];
  79. } sys_patterns;
  80.  
  81. typedef struct {
  82.     Rect r;
  83.     int dir;
  84.     int speed;
  85.     int score;
  86. } paddle;
  87.     
  88. typedef struct {
  89.     RgnHandle    rgn;
  90.     RgnHandle    oldRgn;
  91.     RgnHandle    unRgn;
  92.     int dir;
  93.     int speed;
  94.     int on;
  95. } target;
  96.  
  97. typedef struct {
  98.     int mode;
  99.     Tone triplet[1];
  100. } bleep_tag;
  101.         
  102. typedef struct {
  103.     int mode;
  104.     Tone triplet[2];
  105. } blat_tag;
  106.     
  107. static bleep_tag bleep_buf;
  108. static blat_tag  blat_buf;
  109. static paddle l_paddle, r_paddle;
  110. static target ball;
  111. static sys_patterns **pat_handle;
  112. static WindowPtr gameWindow, which_window, aboutWindow;
  113. static WindowRecord winStorage;
  114. static Rect r, r2, dragRect, top_wall, bottom_wall;
  115. static EventRecord gameEvent;
  116. static MenuHandle gameMenu[5];
  117. static char menuTitle[1];
  118. static int skill_level, done, paused, last_won, volleys, sound_on;
  119. static char title[] = {
  120.     "\pLeft 00 - Mac Pong - Right 00"
  121. //•    12345678901234567890123456789
  122. };
  123.  
  124. main() 
  125. {
  126.     SetUp();
  127.     HideCursor ();
  128.     
  129.     while (! done)
  130.     {
  131.         Handle_Events();
  132.         Play_Pong();
  133.     }
  134.     FlushEvents(everyEvent, 0);
  135.     StopSound();
  136.     ExitToShell();
  137. }
  138.  
  139. SetUp()
  140. {
  141.     done = 0;
  142.     skill_level = 2;
  143.     sound_on = 1;
  144.     last_won = RIGHT;
  145.     InitGraf(&qd.thePort);
  146.     InitFonts();
  147.     InitWindows();
  148.     TEInit();
  149.     InitDialogs(0);
  150.     InitCursor();
  151.     InitSounds();
  152.     pat_handle = (sys_patterns**) GetResource('PAT#', 0);
  153.  
  154.     FlushEvents(everyEvent, 0);
  155.  
  156.     SetRect(&r, 4, 40, 508, 338);
  157.     SetRect(&dragRect, 4, 24, r.right - 4, r.bottom - 4);
  158.     
  159. //     gameWindow = NewWindow(&winStorage, 
  160. //                 &r, "\pLeft 00 MAC_Pong Right 00", 
  161. //                  1, rDocProc, (WindowPtr)-1L, 0, 0L);
  162.                  
  163.     gameWindow = NewWindow(&winStorage, &r, title, 1, rDocProc, (WindowPtr)-1L, 0, 0L);
  164.  
  165.     SetPort(gameWindow);
  166.     Build_Menus();
  167.     ShowCursor();
  168.     Create_L_Paddle();
  169.     Create_R_Paddle();
  170.     Create_Walls();
  171.     Create_Ball();
  172.     Init_Game();
  173. }
  174.  
  175. /* pretty much straight from SAMP in I.M. */
  176. Handle_Events()
  177. {
  178.     SystemTask(); 
  179.     if (GetNextEvent(everyEvent, &gameEvent))
  180.     {
  181.         switch (gameEvent.what)
  182.         {
  183.             case mouseDown:
  184.                 ShowCursor ();
  185.                 switch (FindWindow(gameEvent.where, &which_window))
  186.                 {
  187.                     case inMenuBar:
  188.                         DoCommand(MenuSelect(gameEvent.where));
  189.                     break;
  190.                     case inSysWindow:
  191.                         SystemClick(&gameEvent, which_window);
  192.                     break;
  193.                     case inDrag:
  194.                         DragWindow(which_window, gameEvent.where, &dragRect);
  195.                     break;
  196.                     case inContent:
  197.                         if (which_window != FrontWindow())
  198.                             SelectWindow(which_window);
  199.                     break;
  200.                 }
  201.             break;
  202.  
  203.             case keyDown: 
  204.             case autoKey:
  205.                 if ((gameEvent.modifiers & cmdKey) != 0)
  206.                 {
  207. //                    AdjustMenus();
  208.                     DoCommand(MenuKey((char) (gameEvent.message & charCodeMask)));
  209.                 }
  210.             break;
  211.  
  212.             case activateEvt:
  213.                 if (gameEvent.modifiers & activeFlag)
  214.                     Disable_Edit_Menu();
  215.                 else
  216.                     Enable_Edit_Menu();
  217.             break;
  218.             
  219.             case updateEvt:
  220.                 SetPort(gameWindow);
  221.                 BeginUpdate(gameWindow);
  222.                 FillRect(&l_paddle.r, PAD_PAT);
  223.                 FillRect(&r_paddle.r, PAD_PAT);
  224.                 FillRect(&top_wall, WALL_PAT);
  225.                 FillRect(&bottom_wall, WALL_PAT);
  226.                 if (ball.on)
  227.                     PaintRgn(ball.rgn);
  228.                 EndUpdate(gameWindow);
  229.             break;
  230.         }
  231.     }
  232. }
  233.  
  234. Play_Pong()
  235. {
  236.     if ( (! paused) && (l_paddle.score < HIGHSCORE && r_paddle.score < HIGHSCORE))
  237.     {
  238.         if (! ball.on)
  239.             Serve_Ball();
  240.         Check_Status();
  241.         Move_Left_Paddle();
  242.         Move_Right_Paddle();
  243.         Move_Ball();
  244.     }
  245. }
  246.  
  247. InitSounds()
  248. {
  249.     bleep_buf.mode = swMode;
  250.     bleep_buf.triplet[0].count = 1000;
  251.     bleep_buf.triplet[0].amplitude = 255;
  252.     bleep_buf.triplet[0].duration = 5;
  253.     blat_buf.mode = swMode;
  254.     blat_buf.triplet[0].count = 1000;
  255.     blat_buf.triplet[0].amplitude = 255;
  256.     blat_buf.triplet[0].duration = 5;
  257.     blat_buf.triplet[1].count = 3000;
  258.     blat_buf.triplet[1].amplitude = 255;
  259.     blat_buf.triplet[1].duration = 10; 
  260. }
  261.  
  262. Build_Menus()
  263. {
  264.     register int i;
  265.     
  266.     InitMenus();
  267.     gameMenu[0] = NewMenu(appleID, "\p\024");
  268.     gameMenu[1] = NewMenu(fileID, "\pFile");
  269.     gameMenu[2] = NewMenu(editID, "\pEdit");
  270.     gameMenu[3] = NewMenu(skillID, "\pSkill");
  271.     gameMenu[4] = NewMenu(soundID, "\pSound");
  272.     AppendMenu(gameMenu[0],"\pAbout \"Pong\"");
  273.     AddResMenu(gameMenu[0],'DRVR');
  274.     AppendMenu(gameMenu[1],"\pPause/P;Restart/R;Quit/Q");
  275.     AppendMenu(gameMenu[2],"\p(Undo/Z;(-;(Cut/X;(Copy/C;(Paste/V;(Clear");
  276.     AppendMenu(gameMenu[3],"\pBeginner/B;Novice/N;Normal;Expert/E");
  277.     AppendMenu(gameMenu[4],"\pSound Off/S");
  278.     for(i = 0; i < 5; i++)
  279.         InsertMenu(gameMenu[i], 0);
  280.     CheckItem(gameMenu[3], skill_level, 1);
  281.     DrawMenuBar();
  282. }
  283.  
  284. Disable_Edit_Menu()
  285. {
  286.     DisableItem(gameMenu[2], 1);
  287.     DisableItem(gameMenu[2], 3);
  288.     DisableItem(gameMenu[2], 4);
  289.     DisableItem(gameMenu[2], 5);
  290.     DisableItem(gameMenu[2], 6);
  291. }
  292.  
  293. Enable_Edit_Menu()
  294. {
  295.     EnableItem(gameMenu[2], 1);
  296.     EnableItem(gameMenu[2], 3);
  297.     EnableItem(gameMenu[2], 4);
  298.     EnableItem(gameMenu[2], 5);
  299.     EnableItem(gameMenu[2], 6);
  300. }
  301.  
  302. DoCommand (long menu_selection)
  303. {
  304.     register int the_item;
  305.     static char name[256];
  306.     
  307.     the_item = LoWord(menu_selection);
  308.     switch (HiWord(menu_selection))
  309.     {
  310.         case appleID:
  311.             GetItem(gameMenu[0], the_item, name);
  312.             OpenDeskAcc(name);
  313.             SetPort(gameWindow);
  314.         break;
  315.         
  316.         case editID:
  317.             SystemEdit(the_item - 1);
  318.         break;
  319.         
  320.         case fileID:
  321.             switch (the_item)
  322.             {
  323.                 case 1:
  324.                     if (paused)
  325.                     {
  326.                         paused = 0;
  327.                         SetItem(gameMenu[1], 1, "\pPause");
  328.                         ShowCursor ();
  329.                     }
  330.                     else
  331.                         {
  332.                             paused = 1;
  333.                             SetItem(gameMenu[1], 1, "\pContinue");
  334.                             HideCursor ();
  335.                     }
  336.                 break;
  337.                 
  338.                 case 2:
  339.                     Init_Game();
  340.                     HideCursor ();
  341.                 break;
  342.                 
  343.                 case 3:
  344.                     done = 1;
  345.                 break;
  346.             }
  347.         break;
  348.         
  349.         case skillID:
  350.             CheckItem(gameMenu[3], skill_level, 0);
  351.             skill_level = the_item;
  352.             CheckItem(gameMenu[3], skill_level, 1);
  353.             HideCursor ();
  354.         break;
  355.         
  356.         case soundID:
  357.             if (sound_on)
  358.             {
  359.                 sound_on = 0;
  360.                 SetItem(gameMenu[4], 1, "\pSound On");
  361.             }
  362.             else
  363.                 {
  364.                     sound_on = 1;
  365.                     SetItem(gameMenu[4], 1, "\pSound Off");
  366.             }
  367.             HideCursor ();
  368.         break;
  369.     }
  370.     HiliteMenu(0);
  371. }
  372.  
  373. Create_L_Paddle()
  374. {    
  375.     l_paddle.dir = STOPPED;
  376.     l_paddle.speed = PADDLESPEED;
  377.     l_paddle.score = 0;
  378.     SetRect (&l_paddle.r, 
  379.             winStorage.port.portRect.left + PADINSET,
  380.             winStorage.port.portRect.top + PADINSET,
  381.             winStorage.port.portRect.left + PADINSET + PADWIDTH,
  382.             winStorage.port.portRect.top + PADINSET + PADLENGTH);
  383.     FillRect(&l_paddle.r, PAD_PAT);
  384. }
  385.  
  386. Create_R_Paddle()
  387. {    
  388.     r_paddle.dir = STOPPED;
  389.     r_paddle.speed = PADDLESPEED;
  390.     r_paddle.score = 0;
  391.     SetRect (&r_paddle.r,
  392.             winStorage.port.portRect.right - PADWIDTH - PADINSET,
  393.             winStorage.port.portRect.top + PADINSET,
  394.             winStorage.port.portRect.right - PADWIDTH - PADINSET + PADWIDTH,
  395.             winStorage.port.portRect.top + PADINSET + PADLENGTH);
  396.     FillRect(&r_paddle.r, PAD_PAT);    
  397. }    
  398.  
  399. Create_Walls()
  400. {
  401.     SetRect(&top_wall,
  402.             winStorage.port.portRect.left + 20,
  403.             winStorage.port.portRect.top + 5,
  404.             winStorage.port.portRect.right - 20, 
  405.             winStorage.port.portRect.top + 20);
  406.     FillRect(&top_wall, WALL_PAT);
  407.     SetRect(&bottom_wall,
  408.             winStorage.port.portRect.left + 20,
  409.             winStorage.port.portRect.bottom - 20,
  410.             winStorage.port.portRect.right - 20,
  411.             winStorage.port.portRect.bottom - 5);
  412.     FillRect(&bottom_wall, WALL_PAT);    
  413. }
  414.  
  415. Create_Ball()
  416. {
  417.     ball.rgn = NewRgn();
  418.     ball.oldRgn = NewRgn();
  419.     ball.unRgn = NewRgn();
  420.     ball.dir = LEFT;
  421.     ball.speed = BALLSPEED;
  422.     SetRect (&r, 250,  150, 250 + BALLWIDTH, 150 + BALLLENGTH);
  423.     OpenRgn();
  424.     FrameOval(&r);
  425.     CloseRgn(ball.rgn);
  426. }
  427.  
  428. Serve_Ball()
  429. {
  430.     register i;
  431.  
  432.     OffsetRgn(ball.rgn, 250 - ((**ball.rgn).rgnBBox.right),
  433.                         150 - ((**ball.rgn).rgnBBox.top) );
  434.     for (i = 0; i < 250; i++)
  435.     {
  436.         Check_Status();
  437.         Move_Right_Paddle();
  438.         Move_Left_Paddle();
  439.         Move_Ball();
  440.     }
  441.     ball.dir = (last_won == RIGHT) ? LEFT: RIGHT;
  442.     ball.speed = BALLSPEED;
  443.     ball.on = 1;
  444.     PaintRgn(ball.rgn);
  445.     Bleep();
  446. }
  447.  
  448. /* someone scored a point */
  449. Kill_Ball()
  450. {
  451.     ball.on = volleys = 0;
  452.     CopyRgn(ball.rgn, ball.unRgn);
  453.     EraseRgn(ball.rgn);
  454.     Recover_From_Collision();
  455.     Blat();
  456.     Display_Score();
  457. }
  458.  
  459. Init_Game()
  460. {
  461.     l_paddle.score = r_paddle.score = 0;
  462.     ball.speed = BALLSPEED;
  463.     Kill_Ball();
  464. }
  465.  
  466. /* check for bounces, direction changes, scoring, etc */
  467. Check_Status()
  468. {
  469.     static Rect *ball_r;
  470.  
  471.     register ball_top        = (**ball.rgn).rgnBBox.top;
  472.     register ball_bottom    = (**ball.rgn).rgnBBox.bottom;
  473.     register ball_left        = (**ball.rgn).rgnBBox.left;
  474.     register ball_right        = (**ball.rgn).rgnBBox.right;
  475.     
  476.     ball_r = &((**ball.rgn).rgnBBox);
  477.  
  478.     /* make it a little harder as time goes by */
  479.     if (volleys > 35)
  480.         ball.speed = BALLSPEED + 6;
  481.     else if (volleys > 30)
  482.         ball.speed = BALLSPEED + 5;
  483.     else if (volleys > 25)
  484.         ball.speed = BALLSPEED + 4;
  485.     else if (volleys > 20)
  486.         ball.speed = BALLSPEED + 3;
  487.     else if (volleys > 15)
  488.         ball.speed = BALLSPEED + 2;
  489.     else if (volleys > 10)
  490.         ball.speed = BALLSPEED + 1;
  491.         
  492.     r_paddle.speed = ball.speed + 2;
  493.         
  494.     /* the right paddle tries to track the ball */
  495.     if ( (ball_right > 250) &&
  496.          (ball.dir == UP_RIGHT || ball.dir == DOWN_RIGHT || 
  497.           ball.dir == RIGHT) ){
  498.         if (ball_top + Handicap() < r_paddle.r.top)
  499.             r_paddle.dir = UP;
  500.         else if (ball_bottom - Handicap() > r_paddle.r.bottom)
  501.             r_paddle.dir = DOWN;
  502.         else
  503.             r_paddle.dir = STOPPED;
  504.     }
  505.     else
  506.         r_paddle.dir = STOPPED;
  507.         
  508.     /* the ball and the left boundry */
  509.     if (ball_left < l_paddle.r.right ){
  510.         if (SectRect(ball_r, &l_paddle.r, &r))
  511.         {
  512.             volleys++;
  513.             Bleep();
  514.             if (ball_top <= l_paddle.r.top + 15)
  515.                 ball.dir = UP_RIGHT;
  516.             else if (ball_top > l_paddle.r.top + 15 && ball_bottom < l_paddle.r.top + 30)
  517.                 ball.dir = RIGHT;
  518.             else
  519.                 ball.dir = DOWN_RIGHT;
  520.         }
  521.         else{
  522.             last_won = RIGHT;
  523.             r_paddle.score++;
  524.             Kill_Ball();
  525.         }
  526.         return;
  527.     }
  528.     
  529.     /* the ball and the right boundry */
  530.     if (ball_right > r_paddle.r.left){
  531.         if (SectRect(ball_r, &r_paddle.r, &r)){
  532.             volleys++;
  533.             Bleep();
  534.             if (ball_top <= r_paddle.r.top + 15)
  535.                 ball.dir = UP_LEFT;
  536.             else if (ball_top > r_paddle.r.top + 15 && ball_bottom < r_paddle.r.top + 30)
  537.                 ball.dir = LEFT;
  538.             else
  539.                 ball.dir = DOWN_LEFT;
  540.         }
  541.         else{
  542.             last_won = LEFT;
  543.             l_paddle.score++;
  544.             Kill_Ball();
  545.         }
  546.         return;
  547.     }
  548.     
  549.     /* the ball and the top wall */
  550.     if (ball_top < top_wall.bottom){
  551.         if (ball.dir == UP_LEFT)
  552.             ball.dir = DOWN_LEFT;
  553.         else if (ball.dir == UP_RIGHT)
  554.             ball.dir = DOWN_RIGHT;
  555.         Bleep();
  556.         return;
  557.     }
  558.     
  559.     /* the ball and the bottom wall */
  560.     if (ball_bottom > bottom_wall.top){
  561.         if (ball.dir == DOWN_LEFT)
  562.             ball.dir = UP_LEFT;
  563.         else if (ball.dir == DOWN_RIGHT)
  564.             ball.dir = UP_RIGHT;
  565.         Bleep();
  566.         return;
  567.     }
  568. }
  569.  
  570. /* the ball eats the walls and paddles */
  571. Recover_From_Collision()
  572. {
  573.     register Rect *rp = &((**ball.unRgn).rgnBBox);
  574.  
  575.     if (SectRect(rp, &top_wall, &r))
  576.         FillRect(&r, WALL_PAT);
  577.     else if (SectRect(rp, &bottom_wall, &r))
  578.         FillRect(&r, WALL_PAT);
  579.     if (SectRect(rp, &l_paddle.r, &r))
  580.         FillRect(&r, PAD_PAT);
  581.     else if (SectRect(rp, &r_paddle.r, &r))
  582.         FillRect(&r, PAD_PAT);
  583. }
  584.  
  585. Move_Left_Paddle()
  586. {
  587.     static Point mouseLoc;
  588.     register int newTop, newBottom;
  589.  
  590.     GetMouse(&mouseLoc);
  591.     if (mouseLoc.v != l_paddle.r.top)
  592.     {
  593.         r.left = l_paddle.r.left;
  594.         r.right = l_paddle.r.right;
  595.         if (mouseLoc.v <= winStorage.port.portRect.top)
  596.         {
  597.             newTop = winStorage.port.portRect.top;
  598.             newBottom = newTop + PADLENGTH;
  599.         }
  600.         else if (mouseLoc.v + PADLENGTH >= winStorage.port.portRect.bottom){
  601.             newBottom = winStorage.port.portRect.bottom;
  602.             newTop = newBottom - PADLENGTH;
  603.         }
  604.         else{
  605.             newTop = mouseLoc.v;
  606.             newBottom = newTop + PADLENGTH;
  607.         }
  608.         if (newTop > l_paddle.r.top)
  609.         {
  610.             r.top = l_paddle.r.top;
  611.             r.bottom = (newTop > l_paddle.r.bottom) ? l_paddle.r.bottom: newTop;
  612.         }
  613.         else if (newTop < l_paddle.r.top){
  614.             r.bottom = l_paddle.r.bottom;
  615.             r.top = (newBottom < l_paddle.r.top) ? l_paddle.r.top: newBottom;
  616.         }
  617.         l_paddle.r.top = newTop;
  618.         l_paddle.r.bottom = newBottom;
  619.         EraseRect(&r); 
  620.         FillRect(&l_paddle.r, PAD_PAT);
  621.     }
  622.     else
  623.         FillRect(&l_paddle.r, PAD_PAT);
  624. }
  625.  
  626. Move_Right_Paddle()
  627. {
  628.     if (r_paddle.dir == STOPPED)
  629.         FillRect(&r_paddle.r, PAD_PAT);
  630.     else{
  631.         r.left = r_paddle.r.left;
  632.         r.right = r_paddle.r.right;
  633.         switch (r_paddle.dir)
  634.         {
  635.             case UP:
  636.                 r.bottom = r_paddle.r.bottom;
  637.                 r_paddle.r.top -= r_paddle.speed;
  638.                 r_paddle.r.bottom -= r_paddle.speed;
  639.                 r.top = r_paddle.r.bottom;
  640.             break;
  641.             case DOWN:
  642.                 r.top = r_paddle.r.top;
  643.                 r_paddle.r.top += r_paddle.speed;
  644.                 r_paddle.r.bottom += r_paddle.speed;
  645.                 r.bottom = r_paddle.r.top;
  646.             break;    
  647.         }
  648.         EraseRect(&r); 
  649.         FillRect(&r_paddle.r, PAD_PAT);
  650.     }
  651. }
  652.  
  653. Move_Ball()
  654. {
  655.     if (ball.on){
  656.         CopyRgn(ball.rgn, ball.oldRgn);
  657.         switch (ball.dir)
  658.         {
  659.             case LEFT:
  660.                 OffsetRgn(ball.rgn, -ball.speed, 0);
  661.             break;
  662.             case RIGHT:
  663.                 OffsetRgn(ball.rgn, ball.speed, 0);
  664.             break;
  665.             case UP_LEFT:
  666.                 OffsetRgn(ball.rgn, -ball.speed, -ball.speed);
  667.             break;
  668.             case UP_RIGHT:
  669.                 OffsetRgn(ball.rgn, ball.speed, -ball.speed);
  670.             break;
  671.             case DOWN_LEFT:
  672.                 OffsetRgn(ball.rgn, -ball.speed, ball.speed);
  673.             break;
  674.             case DOWN_RIGHT:
  675.                 OffsetRgn(ball.rgn, ball.speed, ball.speed);
  676.             break;
  677.         }
  678.         UnionRgn(ball.rgn, ball.oldRgn, ball.unRgn);
  679.         DiffRgn(ball.unRgn, ball.rgn, ball.unRgn);
  680.         EraseRgn(ball.unRgn);
  681.         PaintRgn(ball.rgn);
  682.         Recover_From_Collision();
  683.     }
  684. }
  685.  
  686. Display_Score()
  687. {
  688.     static long i;
  689.     
  690.         if (l_paddle.score < 10)
  691.         {
  692.             title[6] = '0';
  693.             i = l_paddle.score;
  694.             NumToString(i, (title + 5));
  695.         }
  696.         else{
  697.             i = l_paddle.score;
  698.             NumToString(i, (title + 6));
  699.         }
  700.         if (r_paddle.score < 10)
  701.         {
  702.             title[28] = '0';
  703.             i = r_paddle.score;
  704.             NumToString(i, (title + 27));
  705.         }
  706.         else
  707.             {
  708.                 i = r_paddle.score;
  709.                 NumToString(i, (title + 27));
  710.         }
  711.         /* NumToString inserts a '\0' we don't need */
  712.         *(title + 5) = ' ';
  713.         *(title + 27) = ' ';
  714.         SetWTitle(gameWindow, title);
  715. }
  716.  
  717. Bleep()
  718. {
  719.     if (sound_on)
  720.     {
  721.         if (! SoundDone())
  722.             StopSound();
  723.         StartSound((Ptr) &bleep_buf, (long) sizeof(bleep_buf), 0L);
  724.     }
  725. }
  726.  
  727. Blat()
  728. {
  729.     if (sound_on)
  730.     {
  731.         if (! SoundDone())
  732.             StopSound();
  733.         StartSound((Ptr) &blat_buf, (long) sizeof(blat_buf), 0L);
  734.     }
  735. }
  736.  
  737. /* Every so often, let the Mac's paddle fail to track the ball until
  738.    the ball has passed it by a certain amount.
  739.    This is the heart of a satisfying game. */
  740. int Handicap()
  741. {
  742.     register mac_skill;
  743.  
  744.     switch(skill_level)
  745.     {
  746.         case 1:
  747.             mac_skill = 2;
  748.         break;
  749.         
  750.         case 2:
  751.             mac_skill = 8;
  752.         break;
  753.         case 3:
  754.             mac_skill = 27;
  755.         break;
  756.         
  757.         case 4:
  758.             mac_skill = 64;
  759.         break;
  760.         
  761.         default:
  762.             mac_skill = 2;
  763.         break;
  764.     }
  765.     return ((Random() % mac_skill) == 0) ? 5: 0;
  766. }
  767.  
  768.